#ifndef TEST_BLOCK_BLOCK_HHMM
#define TEST_BLOCK_BLOCK_HHMM

#include <NTL/mat_ZZ.h>
#include <helib/helib.h>

#include "hypercube/hypercube_hmm_engine.hpp"

typedef std::vector<std::vector<helib::Ctxt>> mat_ctxt;
typedef std::vector<std::vector<NTL::mat_ZZ>> mat_ptxt;

struct metrics {
  void report(std::ostream &os = std::cout) const;

  double mat_total = 0.0;
  double mat_add = 0.0;
  double mat_mul = 0.0;

  double noise_m0 = 0.0;
  double noise_m1 = 0.0;
  double noise_m2 = 0.0;
  double noise_m3 = 0.0;
  double noise_m4 = 0.0;
  double noise_m5 = 0.0;
  double noise_m6 = 0.0;

  std::vector<std::vector<double>> noise;
};

void blk_matmul(mat_ctxt &C, const mat_ctxt &A, const mat_ctxt &B,
                hypercube_hmme &hmme, MATRIX_TYPE type, metrics &metric);

void strassen(mat_ctxt &C, const mat_ctxt &A, const mat_ctxt &B,
              hypercube_hmme &hmme, MATRIX_TYPE type, metrics &metric);

void strassen_ptxt(mat_ptxt &C, const mat_ptxt &A, const mat_ptxt &B);

#endif /* TEST_BLOCK_BLOCK_HHMM */
